View Javadoc

1   // SinglePassBootImage.java, created Tue Aug 10 23:23:20 2004 by joewhaley
2   // Copyright (C) 2001-3 John Whaley <jwhaley@alum.mit.edu>
3   // Licensed under the terms of the GNU LGPL; see COPYING for details.
4   package joeq.Bootstrap;
5   
6   import java.util.Collection;
7   import java.util.HashMap;
8   import java.util.HashSet;
9   import java.util.Iterator;
10  import java.util.LinkedList;
11  import java.util.List;
12  import java.util.Map;
13  import java.util.Set;
14  import java.io.DataOutput;
15  import java.io.IOException;
16  import java.io.PrintStream;
17  import java.lang.reflect.Array;
18  import java.nio.ByteBuffer;
19  import java.nio.ByteOrder;
20  import java.nio.MappedByteBuffer;
21  import java.nio.channels.FileChannel;
22  import java.nio.channels.FileChannel.MapMode;
23  import joeq.Allocator.CodeAllocator;
24  import joeq.Allocator.ObjectLayout;
25  import joeq.Assembler.Code2CodeReference;
26  import joeq.Assembler.Code2HeapReference;
27  import joeq.Assembler.DirectBindCall;
28  import joeq.Assembler.ExternalReference;
29  import joeq.Assembler.Heap2CodeReference;
30  import joeq.Assembler.Heap2HeapReference;
31  import joeq.Assembler.Reloc;
32  import joeq.Class.PrimordialClassLoader;
33  import joeq.Class.jq_Array;
34  import joeq.Class.jq_Class;
35  import joeq.Class.jq_CompiledCode;
36  import joeq.Class.jq_InstanceField;
37  import joeq.Class.jq_Member;
38  import joeq.Class.jq_Method;
39  import joeq.Class.jq_Primitive;
40  import joeq.Class.jq_Reference;
41  import joeq.Class.jq_StaticField;
42  import joeq.Class.jq_StaticMethod;
43  import joeq.Class.jq_Type;
44  import joeq.Linker.ELF.ELF;
45  import joeq.Linker.ELF.ELFConstants;
46  import joeq.Linker.ELF.ELFOutput;
47  import joeq.Linker.ELF.RelocEntry;
48  import joeq.Linker.ELF.Section;
49  import joeq.Linker.ELF.SymbolTableEntry;
50  import joeq.Memory.Address;
51  import joeq.Memory.CodeAddress;
52  import joeq.Memory.HeapAddress;
53  import joeq.Runtime.ExceptionDeliverer;
54  import joeq.Runtime.Reflection;
55  import joeq.Runtime.SystemInterface;
56  import joeq.Runtime.Unsafe;
57  import joeq.Scheduler.jq_NativeThread;
58  import jwutil.collections.IdentityHashCodeWrapper;
59  import jwutil.collections.Pair;
60  import jwutil.io.DataOutputByteBuffer;
61  import jwutil.strings.Strings;
62  import jwutil.util.Assert;
63  
64  /***
65   * SinglePassBootImage
66   *
67   * @author  John Whaley <jwhaley@alum.mit.edu>
68   * @version $Id: SinglePassBootImage.java 2475 2006-12-24 09:44:50Z joewhaley $
69   */
70  public class SinglePassBootImage implements ELFConstants {
71  
72      public static int MAX_HEAP = 64000000;
73  
74      {
75          Assert._assert(ObjectLayout.ARRAY_LENGTH_OFFSET == -12);
76          Assert._assert(ObjectLayout.STATUS_WORD_OFFSET == -8);
77          Assert._assert(ObjectLayout.VTABLE_OFFSET == -4);
78          Assert._assert(ObjectLayout.OBJ_HEADER_SIZE == 8);
79          Assert._assert(ObjectLayout.ARRAY_HEADER_SIZE == 12);
80      }
81      
82      public static /*final*/ boolean TRACE = false;
83      public static final PrintStream out = System.out;
84      
85      public static final SinglePassBootImage DEFAULT = new SinglePassBootImage(BootstrapCodeAllocator.DEFAULT);
86      
87      private final Map/*<IdentityHashCodeWrapper, Entry>*/ hash;
88      private final LinkedList/*<Entry>*/ forwardRefs;
89      private ByteBuffer heapBuffer;
90      private final int startAddress;
91      private int heapCurrent;
92  
93      private BootstrapCodeAllocator bca;
94      private Collection data_relocs;
95      
96      public Set boot_types;
97      
98      public final Collection toReinitialize;
99      
100     boolean MULTI_RELOCS = false;
101     
102     public SinglePassBootImage(BootstrapCodeAllocator bca, int initialCapacity, float loadFactor) {
103         this.hash = new HashMap(initialCapacity, loadFactor);
104         this.bca = bca;
105         this.heapCurrent = this.startAddress = 0;
106         this.data_relocs = true // MULTI_RELOCS
107             ? (Collection) new HashSet() : new LinkedList();
108         this.forwardRefs = new LinkedList();
109         this.toReinitialize = new HashSet();
110         this.heapBuffer = 
111             //ByteBuffer.allocate(MAX_HEAP);
112             ByteBuffer.allocateDirect(MAX_HEAP);
113         heapBuffer.order(ByteOrder.LITTLE_ENDIAN);
114         heapBuffer.limit(MAX_HEAP);
115     }
116     public SinglePassBootImage(BootstrapCodeAllocator bca, int initialCapacity) {
117         this(bca, initialCapacity, 0.75f);
118     }
119     public SinglePassBootImage(BootstrapCodeAllocator bca) {
120         this(bca, 1000000);
121     }
122     
123     public final HeapAddress addressOf(Object o) {
124         Assert._assert(!(o instanceof BootstrapAddress));
125         return getOrAllocateObject(o);
126     }
127     
128     public final void addCodeReloc(HeapAddress addr, CodeAddress target) {
129         if (TRACE) out.println("Adding reloc: heap "+addr.stringRep()+" to code "+target.stringRep());
130         Heap2CodeReference r = new Heap2CodeReference(addr, target);
131         boolean b = data_relocs.add(r);
132         if (!MULTI_RELOCS) Assert._assert(b);
133     }
134     public final void addDataReloc(HeapAddress addr, HeapAddress target) {
135         if (TRACE) out.println("Adding reloc: heap "+addr.stringRep()+" to heap "+target.stringRep());
136         Heap2HeapReference r = new Heap2HeapReference(addr, target);
137         boolean b = data_relocs.add(r);
138         if (!MULTI_RELOCS) Assert._assert(b);
139     }
140     
141     public final void invokeclinit(jq_Class c) {
142         // call forName on this type to trigger class initialization
143         String cname = c.getName().toString();
144         try {
145             Class.forName(cname);
146         } catch (ClassNotFoundException x) {
147             // bootstrapping jvm can't find the class?
148             System.err.println("ERROR: bootstrapping jvm cannot find class "+cname);
149             Assert.UNREACHABLE();
150         }
151     }
152 
153     private boolean alloc_enabled = false;
154     
155     public void enableAllocations() { alloc_enabled = true; }
156     public void disableAllocations() { alloc_enabled = false; }
157     
158     public HeapAddress isInitialized(Object o) {
159         IdentityHashCodeWrapper k = IdentityHashCodeWrapper.create(o);
160         HeapAddress e = (HeapAddress) hash.get(k);
161         return e;
162     }
163     
164     public HeapAddress initializeObject(Object o) {
165         IdentityHashCodeWrapper k = IdentityHashCodeWrapper.create(o);
166         HeapAddress e = (HeapAddress) hash.get(k);
167         if (e != null) {
168             // Need to re-initialize data.
169             layoutObject(o, e, MULTI_RELOCS);
170             return e;
171         } else {
172             // Object not allocated yet, allocate and initialize it now.
173             return getOrAllocateObject(o);
174         }
175     }
176     
177     public HeapAddress getOrAllocateObject(Object o) {
178         if (o == null) return HeapAddress.getNull();
179         //jq.Assert(!(o instanceof BootstrapAddress));
180         IdentityHashCodeWrapper k = IdentityHashCodeWrapper.create(o);
181         HeapAddress e = (HeapAddress) hash.get(k);
182         if (e != null) return e;
183         // not yet allocated, allocate it.
184         Assert._assert(alloc_enabled);
185         Class objType = o.getClass();
186         try {
187             jq_Reference type = (jq_Reference)Reflection.getJQType(objType);
188             if (!boot_types.contains(type)) {
189                 System.err.println("--> class "+type+" is not in the set of boot types!");
190                 //new Exception().printStackTrace();
191                 return HeapAddress.getNull();
192             }
193             Assert._assert(!type.isAddressType());
194             //if (!type.isClsInitialized()) {
195             //    Assert.UNREACHABLE(type.toString());
196             //    return HeapAddress.getNull();
197             //}
198             int addr;
199             int size;
200             if (type.isArrayType()) {
201                 addr = heapCurrent + ObjectLayout.ARRAY_HEADER_SIZE;
202                 size = ((jq_Array)type).getInstanceSize(Array.getLength(o));
203                 size = (size+3) & ~3;
204                 if (TRACE)
205                     out.println("Allocating entry "+hash.size()+": "+objType+" length "+Array.getLength(o)+" size "+size+" "+Strings.hex(System.identityHashCode(o))+" at "+Strings.hex(addr));
206             } else {
207                 Assert._assert(type.isClassType());
208                 addr = heapCurrent + ObjectLayout.OBJ_HEADER_SIZE;
209                 size = ((jq_Class)type).getInstanceSize();
210                 if (TRACE)
211                     out.println("Allocating entry "+hash.size()+": "+objType+" size "+size+" "+Strings.hex(System.identityHashCode(o))+" at "+Strings.hex(addr)+((o instanceof jq_Type)?": "+o:""));
212                 Assert._assert(size == ((size+3) & ~3));
213             }
214             heapCurrent += size;
215             BootstrapHeapAddress a = new BootstrapHeapAddress(addr);
216             hash.put(k, a);
217             layoutObject(o, a, true);
218             return a;
219         } catch (Exception ie) {
220             ie.printStackTrace();
221             HashSet visited = new HashSet();
222             UnknownObjectException x = new UnknownObjectException(o);
223             boolean found = findReferencePath(o, x, visited);
224             if (found) {
225                 SinglePassBootImage.out.println(x);
226             }
227             return HeapAddress.getNull();
228         }
229     }
230     
231     public static boolean IGNORE_UNKNOWN_OBJECTS = false;
232     
233     public HeapAddress getAddressOf(HeapAddress from, Object to) {
234         if (to == null) return HeapAddress.getNull();
235         Assert._assert(!(to instanceof BootstrapAddress));
236         IdentityHashCodeWrapper k = IdentityHashCodeWrapper.create(to);
237         HeapAddress e = (HeapAddress) hash.get(k);
238         if (e == null) {
239             if (from == null) {
240                 System.err.println("Unknown object of type: "+to.getClass()+" address: "+Strings.hex(System.identityHashCode(to))+" value: "+to);
241                 if (IGNORE_UNKNOWN_OBJECTS) return HeapAddress.getNull();
242                 throw new UnknownObjectException(to);
243             } else {
244                 if (TRACE)
245                     out.println("Adding forward reference from "+from.stringRep()+" to "+to.getClass()+" "+Strings.hex(System.identityHashCode(to)));
246                 forwardRefs.add(new Pair(from, to));
247                 return HeapAddress.getNull();
248             }
249         }
250         return e;
251     }
252     
253     public void initStaticField(jq_StaticField f) {
254         jq_Class k = f.getDeclaringClass();
255         jq_Type ftype = f.getType();
256         if (ftype.isPrimitiveType()) {
257             if (ftype == jq_Primitive.INT) {
258                 int v = Reflection.getstatic_I(f);
259                 k.setStaticData(f, v);
260             } else if (ftype == jq_Primitive.FLOAT) {
261                 float v = Reflection.getstatic_F(f);
262                 k.setStaticData(f, v);
263             } else if (ftype == jq_Primitive.LONG) {
264                 long v = Reflection.getstatic_L(f);
265                 k.setStaticData(f, v);
266             } else if (ftype == jq_Primitive.DOUBLE) {
267                 double v = Reflection.getstatic_D(f);
268                 k.setStaticData(f, v);
269             } else if (ftype == jq_Primitive.BOOLEAN) {
270                 int v = Reflection.getstatic_Z(f)?1:0;
271                 k.setStaticData(f, v);
272             } else if (ftype == jq_Primitive.BYTE) {
273                 byte v = Reflection.getstatic_B(f);
274                 k.setStaticData(f, v);
275             } else if (ftype == jq_Primitive.SHORT) {
276                 short v = Reflection.getstatic_S(f);
277                 k.setStaticData(f, v);
278             } else if (ftype == jq_Primitive.CHAR) {
279                 char v = Reflection.getstatic_C(f);
280                 k.setStaticData(f, v);
281             } else
282                 Assert.UNREACHABLE();
283         } else if (ftype.isAddressType()) {
284             Address addr = Reflection.getstatic_P(f);
285             if (addr == null) addr = HeapAddress.getNull();
286             if (TRACE) out.println("Initializing static field "+f+" to "+addr.stringRep());
287             k.setStaticData(f, addr);
288         } else {
289             Object val = Reflection.getstatic_A(f);
290             HeapAddress addr = HeapAddress.addressOf(val);
291             if (TRACE) out.println("Initializing static field "+f+" to "+addr.stringRep());
292             k.setStaticData(f, addr);
293         }
294     }
295     
296     public void initStaticFields(jq_Class k) {
297         jq_StaticField[] sfs = k.getDeclaredStaticFields();
298         for (int j=0; j<sfs.length; ++j) {
299             jq_StaticField sf = sfs[j];
300             initStaticField(sf);
301         }
302     }
303     
304     public void initStaticData(jq_Class k) {
305         Object static_data = k.getStaticData();
306         if (static_data != null) {
307             initializeObject(static_data);
308         }
309     }
310     
311     public void addStaticFieldRelocs(jq_Class k) {
312         jq_StaticField[] sfs = k.getDeclaredStaticFields();
313         for (int j=0; j<sfs.length; ++j) {
314             jq_StaticField sf = sfs[j];
315             addStaticFieldReloc(sf);
316         }
317     }
318     
319     public void addStaticFieldReloc(jq_StaticField f) {
320         jq_Type ftype = f.getType();
321         if (f.isCodeAddressType()) {
322             CodeAddress addr = (CodeAddress)Reflection.getstatic_P(f);
323             if (addr != null && !addr.isNull()) {
324                 if (TRACE)
325                     out.println("Adding code reloc for "+f+": "+f.getAddress().stringRep()+" "+addr.stringRep());
326                 addCodeReloc(f.getAddress(), addr);
327             }
328         } else if (f.isHeapAddressType()) {
329             HeapAddress addr = (HeapAddress)Reflection.getstatic_P(f);
330             if (addr != null && !addr.isNull()) {
331                 if (TRACE)
332                     out.println("Adding data reloc for "+f+": "+f.getAddress().stringRep()+" "+addr.stringRep());
333                 addDataReloc(f.getAddress(), addr);
334             }
335         } else if (ftype.isReferenceType()) {
336             Object val = Reflection.getstatic_A(f);
337             if (val != null) {
338                 if (val instanceof BootstrapAddress) {
339                     Assert.UNREACHABLE("Error: "+f+" contains "+((Address)val).stringRep());
340                 }
341                 HeapAddress addr = HeapAddress.addressOf(val);
342                 if (TRACE) out.println("Adding data reloc for "+f+": "+f.getAddress().stringRep()+" "+addr.stringRep());
343                 addDataReloc(f.getAddress(), addr);
344             }
345         }
346     }
347     
348     public void initVTable(jq_Reference t) {
349         Object vtable = t.getVTable();
350         initializeObject(vtable);
351     }
352     
353     public int numOfEntries() { return hash.size(); }
354 
355     public void layoutObject(Object o, HeapAddress addr, boolean addReloc) {
356         Class objType = o.getClass();
357         jq_Reference jqType = (jq_Reference)Reflection.getJQType(objType);
358         if (TRACE)
359             out.println("Laying out object @"+addr.stringRep()+": "+objType+" "+Strings.hex(System.identityHashCode(o)));
360         if (o instanceof java.io.FileDescriptor &&
361             o != java.io.FileDescriptor.in &&
362             o != java.io.FileDescriptor.out &&
363             o != java.io.FileDescriptor.err) {
364             int fd = Reflection.getfield_I(o, ((jq_Class)jqType).getOrCreateInstanceField("fd", "I"));
365             out.println("Warning: File descriptor "+fd+" will not be valid in bootstrap image.");
366             HashSet visited = new HashSet();
367             UnknownObjectException x = new UnknownObjectException(o);
368             boolean found = findReferencePath(o, x, visited);
369             if (found) {
370                 SinglePassBootImage.out.println(x);
371             }
372         }
373         int status = 0;
374         HeapAddress p_vtable = (HeapAddress) addr.offset(ObjectLayout.VTABLE_OFFSET);
375         HeapAddress vtable = getAddressOf(p_vtable, jqType.getVTable());
376         if (addReloc) addDataReloc(p_vtable, vtable);
377         if (jqType.isArrayType()) {
378             int address = addr.offset(-ObjectLayout.ARRAY_HEADER_SIZE).to32BitValue();
379             heapBuffer.position(address);
380             int length = Array.getLength(o);
381             putUInt(heapBuffer, length);
382             putUInt(heapBuffer, status);
383             putAddress(heapBuffer, vtable);
384             jq_Type elemType = ((jq_Array)jqType).getElementType();
385             if (elemType.isPrimitiveType()) {
386                 if (elemType == jq_Primitive.INT) {
387                     int[] v = (int[])o;
388                     for (int k=0; k<length; ++k)
389                         putUInt(heapBuffer, v[k]);
390                 } else if (elemType == jq_Primitive.FLOAT) {
391                     float[] v = (float[])o;
392                     for (int k=0; k<length; ++k)
393                         putUInt(heapBuffer, Float.floatToRawIntBits(v[k]));
394                 } else if (elemType == jq_Primitive.LONG) {
395                     long[] v = (long[])o;
396                     for (int k=0; k<length; ++k)
397                         putULong(heapBuffer, v[k]);
398                 } else if (elemType == jq_Primitive.DOUBLE) {
399                     double[] v = (double[])o;
400                     for (int k=0; k<length; ++k)
401                         putULong(heapBuffer, Double.doubleToRawLongBits(v[k]));
402                 } else if (elemType == jq_Primitive.BOOLEAN) {
403                     boolean[] v = (boolean[])o;
404                     for (int k=0; k<length; ++k)
405                         putUByte(heapBuffer, v[k]?(byte)1:(byte)0);
406                 } else if (elemType == jq_Primitive.BYTE) {
407                     byte[] v = (byte[])o;
408                     for (int k=0; k<length; ++k)
409                         putByte(heapBuffer, v[k]);
410                 } else if (elemType == jq_Primitive.SHORT) {
411                     short[] v = (short[])o;
412                     for (int k=0; k<length; ++k)
413                         putShort(heapBuffer, v[k]);
414                 } else if (elemType == jq_Primitive.CHAR) {
415                     char[] v = (char[])o;
416                     for (int k=0; k<length; ++k)
417                         putUShort(heapBuffer, v[k]);
418                 } else Assert.UNREACHABLE();
419             } else if (elemType.isAddressType()) {
420                 Address[] v = (Address[])o;
421                 for (int k=0; k<length; ++k) {
422                     putAddress(heapBuffer, v[k]==null?HeapAddress.getNull():v[k]);
423                     // This is probably a vtable; relocations are handled elsewhere.
424                 }
425             } else {
426                 Object[] v = (Object[])o;
427                 for (int k=0; k<length; ++k) {
428                     Object o2 = Reflection.arrayload_A(v, k);
429                     HeapAddress p_a2 = (HeapAddress) addr.offset(ObjectLayout.ARRAY_ELEMENT_OFFSET + k*HeapAddress.size());
430                     HeapAddress a2 = getAddressOf(p_a2, o2);
431                     putAddress(heapBuffer, a2);
432                     if (o2 != null) {
433                         if (addReloc) addDataReloc(p_a2, a2);
434                     }
435                 }
436             }
437         } else {
438             int address = addr.offset(-ObjectLayout.OBJ_HEADER_SIZE).to32BitValue();
439             heapBuffer.position(address);
440             Assert._assert(jqType.isClassType());
441             jq_Class clazz = (jq_Class)jqType;
442             putUInt(heapBuffer, status);
443             putAddress(heapBuffer, vtable);
444             if (clazz.isSubtypeOf(jq_Reference._class)) {
445                 // Need to reinitialize "state" field.
446                 if (TRACE) SinglePassBootImage.out.println("Marking "+o+"@"+addr.stringRep()+" to be reinitialized later.");
447                 toReinitialize.add(o);
448             }
449             if (clazz.isSubtypeOf(jq_Member._class)) {
450                 // Need to reinitialize "state" field.
451                 if (TRACE) SinglePassBootImage.out.println("Marking "+o+"@"+addr.stringRep()+" to be reinitialized later.");
452                 toReinitialize.add(o);
453             }
454             jq_InstanceField[] fields = clazz.getInstanceFields();
455             for (int k=0; k<fields.length; ++k) {
456                 jq_InstanceField f = fields[k];
457                 if (f == jq_Method._default_compiled_version) {
458                     // Skip this field, as it is handled later.
459                     int foffset = f.getOffset();
460                     if (TRACE) SinglePassBootImage.out.println("Field "+f+" offset "+Strings.shex(foffset)+": handled later.");
461                     //toReinitialize.add(o);
462                     continue;
463                 }
464                 jq_Type ftype = f.getType();
465                 int foffset = f.getOffset();
466                 HeapAddress p_f = (HeapAddress) addr.offset(foffset);
467                 heapBuffer.position(p_f.to32BitValue());
468                 if (TRACE) SinglePassBootImage.out.println("Field "+f+" offset "+Strings.shex(foffset)+": "+Strings.hex(System.identityHashCode(Reflection.getfield(o, f))));
469                 if (ftype.isPrimitiveType()) {
470                     if (ftype == jq_Primitive.INT)
471                         putUInt(heapBuffer, Reflection.getfield_I(o, f));
472                     else if (ftype == jq_Primitive.FLOAT)
473                         putUInt(heapBuffer, Float.floatToRawIntBits(Reflection.getfield_F(o, f)));
474                     else if (ftype == jq_Primitive.LONG)
475                         putULong(heapBuffer, Reflection.getfield_L(o, f));
476                     else if (ftype == jq_Primitive.DOUBLE)
477                         putULong(heapBuffer, Double.doubleToRawLongBits(Reflection.getfield_D(o, f)));
478                     else if (ftype == jq_Primitive.BOOLEAN)
479                         putUByte(heapBuffer, Reflection.getfield_Z(o, f)?(byte)1:(byte)0);
480                     else if (ftype == jq_Primitive.BYTE)
481                         putByte(heapBuffer, Reflection.getfield_B(o, f));
482                     else if (ftype == jq_Primitive.SHORT)
483                         putShort(heapBuffer, Reflection.getfield_S(o, f));
484                     else if (ftype == jq_Primitive.CHAR)
485                         putUShort(heapBuffer, Reflection.getfield_C(o, f));
486                     else Assert.UNREACHABLE();
487                 } else if (ftype.isAddressType()) {
488                     Address a = Reflection.getfield_P(o, f);
489                     if (f.isCodeAddressType()) {
490                         if (a != null && !a.isNull()) {
491                             putAddress(heapBuffer, a);
492                             if (addReloc) addCodeReloc(p_f, (CodeAddress) a);
493                         } else {
494                             putAddress(heapBuffer, CodeAddress.getNull());
495                         }
496                     } else if (f.isHeapAddressType()) {
497                         if (a != null && !a.isNull()) {
498                             putAddress(heapBuffer, a);
499                             if (addReloc) addDataReloc((HeapAddress) addr.offset(f.getOffset()), (HeapAddress) a);
500                         } else {
501                             putAddress(heapBuffer, HeapAddress.getNull());
502                         }
503                     } else if (f.isStackAddressType()) {
504                         if (a != null && !a.isNull()) {
505                             putAddress(heapBuffer, a);
506                             // no reloc necessary.
507                         } else {
508                             putAddress(heapBuffer, HeapAddress.getNull());
509                         }
510                     } else if (f.getType().isAddressType()) {
511                         Assert.UNREACHABLE("Field has untyped Address type: "+f);
512                     }
513                 } else {
514                     Object val = Reflection.getfield_A(o, f);
515                     HeapAddress a = getAddressOf(p_f, val);
516                     putAddress(heapBuffer, a);
517                     if (val != null) {
518                         if (addReloc) addDataReloc(p_f, a);
519                     }
520                 }
521             }
522         }
523     }
524     
525     public void reinitializeObjects() {
526         for (Iterator i = toReinitialize.iterator(); i.hasNext(); ) {
527             Object o = i.next();
528             HeapAddress addr = getAddressOf(null, o);
529             if (o instanceof jq_Class) {
530                 // Reinitialize state field.
531                 jq_InstanceField f = jq_Reference._state;
532                 HeapAddress p_f = (HeapAddress) addr.offset(f.getOffset());
533                 heapBuffer.position(p_f.to32BitValue());
534                 putInt(heapBuffer, Reflection.getfield_I(o, f));
535                 i.remove();
536             }
537             if (o instanceof jq_Member) {
538                 // Reinitialize state field.
539                 jq_InstanceField f = jq_Member._state;
540                 HeapAddress p_f = (HeapAddress) addr.offset(f.getOffset());
541                 heapBuffer.position(p_f.to32BitValue());
542                 putByte(heapBuffer, Reflection.getfield_B(o, f));
543             }
544             if (o instanceof jq_Method) {
545                 // Set default_compiled_version field and add reloc.
546                 jq_Method m = (jq_Method) o;
547                 jq_InstanceField f = jq_Method._default_compiled_version;
548                 HeapAddress p_f = (HeapAddress) addr.offset(f.getOffset());
549                 if (!m.isInitialized()) {
550                     if (TRACE) out.println("Skipping initialization of default_compiled_code (at "+p_f.stringRep()+") for "+m+" because it is not initialized.");
551                     continue;
552                 }
553                 jq_CompiledCode cc = m.getDefaultCompiledVersion();
554                 if (cc != null) {
555                     HeapAddress target = getOrAllocateObject(cc);
556                     if (TRACE) out.println("Initializing default_compiled_code (at "+p_f.stringRep()+") for "+m+" to "+target.stringRep());
557                     heapBuffer.position(p_f.to32BitValue());
558                     putAddress(heapBuffer, target);
559                     addDataReloc(p_f, target);
560                     i.remove();
561                 }
562             }
563         }
564     }
565     
566     public int size() { return heapCurrent-startAddress; }
567     
568     public static int UPDATE_PERIOD = 10000;
569 
570     public void handleForwardReferences() {
571         int i = 0;
572         while (!forwardRefs.isEmpty()) {
573             if ((i % UPDATE_PERIOD) == 0) {
574                 int total = i + forwardRefs.size();
575                 out.print("Traversing heap: "+i+"/"+total+"\r");
576             }
577             Pair e = (Pair) forwardRefs.removeFirst();
578             HeapAddress from = (HeapAddress) e.left;
579             Object to = e.right;
580             HeapAddress a = getOrAllocateObject(to);
581             if (TRACE)
582                 out.println("Resolving forward reference from "+from.stringRep()+" to "+to.getClass()+" "+Strings.hex(System.identityHashCode(to))+": "+a.stringRep());
583             if (false) {
584                 // This assertion fails when a field reference has changed
585                 // and points to a new object.
586                 int oldValue = heapBuffer.getInt(from.to32BitValue());
587                 Assert._assert(oldValue == HeapAddress.getNull().to32BitValue() ||
588                                oldValue == a.to32BitValue());
589             }
590             putAddressAt(heapBuffer, from.to32BitValue(), a);
591             ++i;
592         }
593     }
594     
595     public static final char F_RELFLG = (char)0x0001;
596     public static final char F_EXEC   = (char)0x0002;
597     public static final char F_LNNO   = (char)0x0004;
598     public static final char F_LSYMS  = (char)0x0008;
599     public static final char F_AR32WR = (char)0x0100;
600     
601     static void putUByte(ByteBuffer out, byte b) {
602         out.put(b);
603     }
604     
605     static void putByte(ByteBuffer out, byte b) {
606         out.put(b);
607     }
608     
609     static void putBytes(ByteBuffer out, byte[] b) {
610         out.put(b);
611     }
612     
613     static void putUShort(ByteBuffer out, char c) {
614         out.putChar(c);
615     }
616     
617     static void putShort(ByteBuffer out, short s) {
618         out.putShort(s);
619     }
620     
621     static void putUInt(ByteBuffer out, int i) {
622         out.putInt(i);
623     }
624     
625     static void putInt(ByteBuffer out, int i) {
626         out.putInt(i);
627     }
628     
629     static void putULong(ByteBuffer out, long i) {
630         out.putLong(i);
631     }
632     
633     static void putAddress(ByteBuffer out, Address a) {
634         out.putInt(a.to32BitValue());
635     }
636     
637     static void putAddressAt(ByteBuffer out, int offset, Address a) {
638         out.putInt(offset, a.to32BitValue());
639     }
640     
641     public void dumpFILHDR(ByteBuffer out, int symptr, int nsyms)
642     throws IOException {
643         out.position(0);
644         // FILHDR
645         putUShort(out, (char)0x014c);  // f_magic
646         putUShort(out, (char)2);       // f_nscns
647         long ms = System.currentTimeMillis();
648         int s = (int)(ms/1000);
649         putUInt(out, s);               // f_timdat
650         putUInt(out, symptr);          // f_symptr
651         putUInt(out, nsyms);           // f_nsyms
652         putUShort(out, (char)0);       // f_opthdr
653         putUShort(out, (char)(F_LNNO | F_LSYMS | F_AR32WR)); // f_flags
654     }
655     
656     public static final int STYP_TEXT  = 0x00000020;
657     public static final int STYP_DATA  = 0x00000040;
658     public static final int STYP_BSS   = 0x00000080;
659     public static final int STYP_RELOV = 0x01000000;
660     public static final int STYP_EXEC  = 0x20000000;
661     public static final int STYP_READ  = 0x40000000;
662     public static final int STYP_WRITE = 0x80000000;
663     
664     public void dumpTEXTSCNHDR(ByteBuffer out, int size, int nreloc)
665     throws IOException {
666         out.position(20);
667         // SCNHDR
668         write_bytes(out, ".text", 8);       // s_name
669         putUInt(out, 0);                // s_paddr
670         putUInt(out, 0);                // s_vaddr
671         putUInt(out, size);             // s_size
672         putUInt(out, 20+40+40);         // s_scnptr
673         putUInt(out, 20+40+40+size);    // s_relptr
674         putUInt(out, 0);                // s_lnnoptr
675         if (nreloc > 65535)
676             putUShort(out, (char)0xffff); // s_nreloc
677         else
678             putUShort(out, (char)nreloc); // s_nreloc
679         putUShort(out, (char)0);         // s_nlnno
680         if (nreloc > 65535)
681             putUInt(out, STYP_TEXT | STYP_READ | STYP_WRITE | STYP_RELOV); // s_flags
682         else
683             putUInt(out, STYP_TEXT | STYP_READ | STYP_WRITE); // s_flags
684     }
685     
686     public void dumpDATASCNHDR(ByteBuffer out, int scnptr, int size, int nreloc)
687     throws IOException {
688         out.position(60);
689         // SCNHDR
690         write_bytes(out, ".data", 8);       // s_name
691         putUInt(out, 0);                // s_paddr
692         putUInt(out, 0);                // s_vaddr
693         putUInt(out, size);             // s_size
694         putUInt(out, scnptr);           // s_scnptr
695         putUInt(out, scnptr+size);      // s_relptr
696         putUInt(out, 0);                // s_lnnoptr
697         if (nreloc > 65535)
698             putUShort(out, (char)0xffff); // s_nreloc
699         else
700             putUShort(out, (char)nreloc); // s_nreloc
701         putUShort(out, (char)0);         // s_nlnno
702         if (nreloc > 65535)
703             putUInt(out, STYP_DATA | STYP_READ | STYP_WRITE | STYP_RELOV); // s_flags
704         else
705             putUInt(out, STYP_DATA | STYP_READ | STYP_WRITE); // s_flags
706     }
707     
708     public static final char RELOC_ADDR32 = (char)0x0006;
709     public static final char RELOC_REL32  = (char)0x0014;
710     
711     public static final short N_UNDEF = 0;
712     public static final short N_ABS   = -1;
713     public static final short N_DEBUG = -2;
714     
715     public static final char T_NULL   = 0x00;
716     public static final char T_VOID   = 0x01;
717     public static final char T_CHAR   = 0x02;
718     public static final char T_SHORT  = 0x03;
719     public static final char T_INT    = 0x04;
720     public static final char T_LONG   = 0x05;
721     public static final char T_FLOAT  = 0x06;
722     public static final char T_DOUBLE = 0x07;
723     public static final char T_STRUCT = 0x08;
724     public static final char T_UNION  = 0x09;
725     public static final char T_ENUM   = 0x0A;
726     public static final char T_MOE    = 0x0B;
727     public static final char T_UCHAR  = 0x0C;
728     public static final char T_USHORT = 0x0D;
729     public static final char T_UINT   = 0x0E;
730     public static final char T_ULONG  = 0x0F;
731     public static final char T_LNGDBL = 0x10;
732     
733     public static final char DT_NON = 0x0000;
734     public static final char DT_PTR = 0x0100;
735     public static final char DT_FCN = 0x0200;
736     public static final char DT_ARY = 0x0300;
737 
738     public static final byte C_NULL   = 0;
739     public static final byte C_AUTO   = 1;
740     public static final byte C_EXT    = 2;
741     public static final byte C_STAT   = 3;
742     public static final byte C_REG    = 4;
743     public static final byte C_EXTDEF = 5;
744     public static final byte C_LABEL  = 6;
745     public static final byte C_ULABEL = 7;
746     public static final byte C_MOS     = 8;
747     public static final byte C_ARG     = 9;
748     public static final byte C_STRTAG  = 10;
749     public static final byte C_MOU     = 11;
750     public static final byte C_UNTAG   = 12;
751     public static final byte C_TPDEF   = 13;
752     public static final byte C_USTATIC = 14;
753     public static final byte C_ENTAG   = 15;
754     public static final byte C_MOE     = 16;
755     public static final byte C_REGPARM = 17;
756     public static final byte C_FIELD   = 18;
757     public static final byte C_AUTOARG = 19;
758     public static final byte C_LASTENT = 20;
759     public static final byte C_BLOCK   = 100;
760     public static final byte C_FCN     = 101;
761     public static final byte C_EOS     = 102;
762     public static final byte C_FILE    = 103;
763     public static final byte C_SECTION = 104;
764     public static final byte C_WEAKEXT = 105;
765     public static final byte C_EFCN    = -1;
766     
767     public void dumpSECTIONSYMENTs(ByteBuffer out)
768     throws IOException {
769         write_bytes(out, ".text", 8);
770         putUInt(out, 0);
771         putShort(out, (short)1);
772         putUShort(out, (char)0);
773         putUByte(out, C_STAT);
774         putUByte(out, (byte)0);
775         
776         write_bytes(out, ".data", 8);
777         putUInt(out, 0);
778         putShort(out, (short)2);
779         putUShort(out, (char)0);
780         putUByte(out, C_STAT);
781         putUByte(out, (byte)0);
782     }
783     
784     public static boolean USE_MICROSOFT_STYLE_MUNGE = true;
785     
786     public static final int NUM_OF_EXTERNAL_SYMS = 9;
787     public void dumpEXTSYMENTs(ByteBuffer out, jq_StaticMethod rootm)
788     throws IOException {
789         // NOTE!!! If you change anything here, be SURE to change the number above!!!
790         String s;
791         if (USE_MICROSOFT_STYLE_MUNGE) s = "_entry@0";
792         else s = "entry";
793         write_bytes(out, s, 8);  // s_name
794         CodeAddress addr = rootm.getDefaultCompiledVersion().getEntrypoint();
795         putUInt(out, addr.to32BitValue());
796         putShort(out, (short)1);
797         putUShort(out, (char)DT_FCN);
798         putUByte(out, C_EXT); // e_sclass
799         putUByte(out, (byte)0); // e_numaux
800         
801         putUInt(out, 0);    // e_zeroes
802         if (USE_MICROSOFT_STYLE_MUNGE) s = "_trap_handler@4";
803         else s = "trap_handler";
804         int idx = alloc_string(s);
805         putUInt(out, idx);  // e_offset
806         addr = ExceptionDeliverer._trap_handler.getDefaultCompiledVersion().getEntrypoint();
807         putUInt(out, addr.to32BitValue());
808         putShort(out, (short)1);
809         putUShort(out, (char)DT_FCN);
810         putUByte(out, C_EXT); // e_sclass
811         putUByte(out, (byte)0); // e_numaux
812 
813         putUInt(out, 0);    // e_zeroes
814         if (USE_MICROSOFT_STYLE_MUNGE) s = "_debug_trap_handler@4";
815         else s = "debug_trap_handler";
816         idx = alloc_string(s);
817         putUInt(out, idx);  // e_offset
818         addr = ExceptionDeliverer._debug_trap_handler.getDefaultCompiledVersion().getEntrypoint();
819         putUInt(out, addr.to32BitValue());
820         putShort(out, (short)1);
821         putUShort(out, (char)DT_FCN);
822         putUByte(out, C_EXT); // e_sclass
823         putUByte(out, (byte)0); // e_numaux
824         
825         putUInt(out, 0);    // e_zeroes
826         if (USE_MICROSOFT_STYLE_MUNGE) s = "_threadSwitch@4";
827         else s = "threadSwitch";
828         idx = alloc_string(s);
829         putUInt(out, idx);  // e_offset
830         addr = jq_NativeThread._threadSwitch.getDefaultCompiledVersion().getEntrypoint();
831         putUInt(out, addr.to32BitValue());
832         putShort(out, (short)1);
833         putUShort(out, (char)DT_FCN);
834         putUByte(out, C_EXT); // e_sclass
835         putUByte(out, (byte)0); // e_numaux
836         
837         putUInt(out, 0);    // e_zeroes
838         if (USE_MICROSOFT_STYLE_MUNGE) s = "_ctrl_break_handler@0";
839         else s = "ctrl_break_handler";
840         idx = alloc_string(s);
841         putUInt(out, idx);  // e_offset
842         addr = jq_NativeThread._ctrl_break_handler.getDefaultCompiledVersion().getEntrypoint();
843         putUInt(out, addr.to32BitValue()); // e_value
844         putShort(out, (short)1);
845         putUShort(out, (char)DT_FCN);
846         putUByte(out, C_EXT); // e_sclass
847         putUByte(out, (byte)0); // e_numaux
848 
849         putUInt(out, 0);    // e_zeroes
850         if (USE_MICROSOFT_STYLE_MUNGE) s = "_joeq_code_startaddress";
851         else s = "joeq_code_startaddress";
852         idx = alloc_string(s);
853         putUInt(out, idx);  // e_offset
854         putUInt(out, 0); // e_value
855         putShort(out, (short)1);
856         putUShort(out, (char)(DT_PTR | T_VOID));
857         putUByte(out, C_EXT); // e_sclass
858         putUByte(out, (byte)0); // e_numaux
859 
860         putUInt(out, 0);    // e_zeroes
861         if (USE_MICROSOFT_STYLE_MUNGE) s = "_joeq_code_endaddress";
862         else s = "joeq_code_endaddress";
863         idx = alloc_string(s);
864         putUInt(out, idx);  // e_offset
865         putUInt(out, textsize); // e_value
866         putShort(out, (short)1);
867         putUShort(out, (char)(DT_PTR | T_VOID));
868         putUByte(out, C_EXT); // e_sclass
869         putUByte(out, (byte)0); // e_numaux
870 
871         putUInt(out, 0);    // e_zeroes
872         if (USE_MICROSOFT_STYLE_MUNGE) s = "_joeq_data_startaddress";
873         else s = "joeq_data_startaddress";
874         idx = alloc_string(s);
875         putUInt(out, idx); // e_offset
876         putUInt(out, 0); // e_value
877         putShort(out, (short)2); // e_scnum
878         putUShort(out, (char)(DT_PTR | T_VOID)); // e_type
879         putUByte(out, C_EXT); // e_sclass
880         putUByte(out, (byte)0); // e_numaux
881         
882         putUInt(out, 0);    // e_zeroes
883         if (USE_MICROSOFT_STYLE_MUNGE) s = "_joeq_data_endaddress";
884         else s = "joeq_data_endaddress";
885         idx = alloc_string(s);
886         putUInt(out, idx); // e_offset
887         putUInt(out, heapCurrent); // e_value
888         putShort(out, (short)2); // e_scnum
889         putUShort(out, (char)(DT_PTR | T_VOID)); // e_type
890         putUByte(out, C_EXT); // e_sclass
891         putUByte(out, (byte)0); // e_numaux
892     }
893     
894     public void dumpEXTDEFSYMENTs(ByteBuffer out, List extrefs)
895     throws IOException {
896         Iterator i = extrefs.iterator();
897         int k = 2+NUM_OF_EXTERNAL_SYMS;
898         while (i.hasNext()) {
899             ExternalReference extref = (ExternalReference)i.next();
900             Assert._assert(extref.getSymbolIndex() == k);
901             String name = extref.getName();
902             if (name.length() <= 8) {
903                 write_bytes(out, name, 8);  // s_name
904             } else {
905                 putUInt(out, 0);    // e_zeroes
906                 int idx = alloc_string(name);
907                 putUInt(out, idx);  // e_offset
908             }
909             putUInt(out, 0);
910             putShort(out, (short)0);
911             putUShort(out, (char)DT_FCN);
912             putUByte(out, C_EXT);
913             putUByte(out, (byte)0);
914             ++k;
915         }
916     }
917     
918     public void dumpMETHODSYMENT(ByteBuffer out, jq_CompiledCode cc)
919     throws IOException {
920         jq_Method m = cc.getMethod();
921         String name;
922         if (m == null) {
923             name = "unknown@"+cc.getEntrypoint().stringRep();
924         } else { 
925             //name = m.getName().toString();
926             name = mungeMemberName(m);
927         }
928         if (name.length() <= 8) {
929             write_bytes(out, name, 8);    // s_name
930         } else {
931             putUInt(out, 0);          // e_zeroes
932             int idx = alloc_string(name);
933             putUInt(out, idx);        // e_offset
934         }
935         CodeAddress addr = cc.getEntrypoint();
936         putUInt(out, addr.to32BitValue()); // e_value
937         putShort(out, (short)1);      // e_scnum
938         putUShort(out, (char)DT_FCN); // e_type
939         putUByte(out, C_EXT);         // e_sclass
940         putUByte(out, (byte)0);             // e_numaux
941     }
942     
943     public void addSystemInterfaceRelocs_COFF(Collection extref, Collection dataRelocs) {
944         jq_StaticField[] fs = SystemInterface._class.getDeclaredStaticFields();
945         int total = 1+NUM_OF_EXTERNAL_SYMS;
946         for (int i=0; i<fs.length; ++i) {
947             jq_StaticField f = fs[i];
948             if (f.isFinal()) continue;
949             if (f.getType() == CodeAddress._class) {
950                 String name = f.getName().toString();
951                 int ind = name.lastIndexOf('_');
952                 if (USE_MICROSOFT_STYLE_MUNGE)
953                     name = "_"+name.substring(0, ind)+"@"+name.substring(ind+1);
954                 else
955                     name = name.substring(0, ind);
956                 if (TRACE) SinglePassBootImage.out.println("External ref="+f+", symndx="+(total+1)+" address="+f.getAddress().stringRep());
957                 ExternalReference r = new ExternalReference(f.getAddress(), name);
958                 r.setSymbolIndex(++total);
959                 extref.add(r);
960                 dataRelocs.add(r);
961             } else if (f.getType() == HeapAddress._class) {
962                 String name = f.getName().toString();
963                 if (USE_MICROSOFT_STYLE_MUNGE)
964                     name = "_"+name;
965                 if (TRACE) SinglePassBootImage.out.println("External ref="+f+", symndx="+(total+1)+" address="+f.getAddress().stringRep());
966                 ExternalReference r = new ExternalReference(f.getAddress(), name);
967                 r.setSymbolIndex(++total);
968                 extref.add(r);
969                 dataRelocs.add(r);
970             }
971         }
972         //return total-3;
973     }
974 
975     public void addSystemInterfaceRelocs_ELF(Collection extref, Collection dataRelocs) {
976         jq_StaticField[] fs = SystemInterface._class.getDeclaredStaticFields();
977         int total = 1+NUM_OF_EXTERNAL_SYMS;
978         for (int i=0; i<fs.length; ++i) {
979             jq_StaticField f = fs[i];
980             if (f.isFinal()) continue;
981             if (f.getType() == CodeAddress._class) {
982                 String name = f.getName().toString();
983                 int ind = name.lastIndexOf('_');
984                 name = name.substring(0, ind);
985                 if (TRACE) SinglePassBootImage.out.println("External ref="+f+", symndx="+(total+1)+" address="+f.getAddress().stringRep());
986                 ExternalReference r = new ExternalReference(f.getAddress(), name);
987                 r.setSymbolIndex(++total);
988                 extref.add(r);
989                 dataRelocs.add(r);
990             } else if (f.getType() == HeapAddress._class) {
991                 String name = f.getName().toString();
992                 if (TRACE) SinglePassBootImage.out.println("External ref="+f+", symndx="+(total+1)+" address="+f.getAddress().stringRep());
993                 ExternalReference r = new ExternalReference(f.getAddress(), name);
994                 r.setSymbolIndex(++total);
995                 extref.add(r);
996                 dataRelocs.add(r);
997             }
998         }
999     }
1000     
1001     public int addVTableRelocs(Collection list) {
1002         int total = 0;
1003         Iterator i = boot_types.iterator();
1004         while (i.hasNext()) {
1005             jq_Type t = (jq_Type)i.next();
1006             if (t.isReferenceType()) {
1007                 if (t == Unsafe._class) continue;
1008                 try {
1009                     if (TRACE) out.println("Adding vtable relocs for: "+t);
1010                     Address[] vtable = (Address[])((jq_Reference)t).getVTable();
1011                     HeapAddress addr = getAddressOf(null, vtable);
1012                     //jq.Assert(vtable[0] != 0, t.toString());
1013                     Heap2HeapReference r1 = new Heap2HeapReference(addr, (HeapAddress) vtable[0]);
1014                     list.add(r1);
1015                     if (TRACE) out.println("Adding reloc: heap "+addr.stringRep()+" to heap "+vtable[0].stringRep());
1016                     for (int j=1; j<vtable.length; ++j) {
1017                         HeapAddress from = (HeapAddress) addr.offset(CodeAddress.size()*j);
1018                         Heap2CodeReference r2 = new Heap2CodeReference(from, (CodeAddress) vtable[j]);
1019                         if (TRACE) out.println("Adding reloc: heap "+from.stringRep()+" to code "+vtable[j].stringRep());
1020                         list.add(r2);
1021                     }
1022                     total += vtable.length;
1023                 } catch (UnknownObjectException x) {
1024                     x.appendMessage("vtable for "+t);
1025                     x.setObject(null);
1026                     throw x;
1027                 }
1028             }
1029         }
1030         return total;
1031     }
1032     
1033     int textsize;
1034     
1035     public void dumpCOFF(FileChannel fc, jq_StaticMethod rootm) throws IOException {
1036         
1037         final List text_relocs1 = bca.getAllCodeRelocs();
1038         final List text_relocs2 = bca.getAllDataRelocs();
1039         
1040         Iterator i = text_relocs1.iterator();
1041         while (i.hasNext()) {
1042             Object r = i.next();
1043             ((Reloc)r).patch();
1044             // directly bound calls do not need to be relocated,
1045             // because they are relative offsets, not absolute addresses.
1046             if (r instanceof DirectBindCall)
1047                 i.remove();
1048         }
1049         
1050         // calculate sizes/offsets
1051         textsize = bca.size();
1052         final List exts = new LinkedList();
1053         final int nlinenum = 0;
1054         int ntextreloc = text_relocs1.size() + text_relocs2.size();
1055         if (ntextreloc > 65535) ++ntextreloc;
1056         final int datastart = 20+40+40+textsize+(10*ntextreloc);
1057         final int datasize = heapCurrent;
1058         final int numOfVTableRelocs = addVTableRelocs(data_relocs);
1059         addSystemInterfaceRelocs_COFF(exts, data_relocs);
1060         int ndatareloc = data_relocs.size();
1061         if (ndatareloc > 65535) ++ndatareloc;
1062         final int symtabstart = datastart+datasize+(10*ndatareloc)+(10*nlinenum);
1063         final int num_ccs = CodeAllocator.getNumberOfCompiledMethods();
1064         final int nsyms = 2+NUM_OF_EXTERNAL_SYMS+num_ccs+exts.size();
1065         final int strtabstart = symtabstart+(18*nsyms);
1066         
1067         if (TRACE) {
1068             SinglePassBootImage.out.println("Text size="+textsize);
1069             SinglePassBootImage.out.println("Num text relocs="+ntextreloc);
1070             SinglePassBootImage.out.println("Data start="+datastart);
1071             SinglePassBootImage.out.println("Data size="+datasize);
1072             SinglePassBootImage.out.println("Num of VTable relocs="+numOfVTableRelocs);
1073             SinglePassBootImage.out.println("Num data relocs="+ntextreloc);
1074             SinglePassBootImage.out.println("Sym tab start="+symtabstart);
1075             SinglePassBootImage.out.println("Num syms="+nsyms);
1076             SinglePassBootImage.out.println("Str tab start="+strtabstart);
1077         }
1078         
1079         out.println("Writing bytes "+0+".."+(datastart-1));
1080         MappedByteBuffer out = fc.map(MapMode.READ_WRITE, 0, datastart);
1081         out.order(ByteOrder.LITTLE_ENDIAN);
1082         
1083         // write file header
1084         dumpFILHDR(out, symtabstart, nsyms);
1085         
1086         // write section headers
1087         dumpTEXTSCNHDR(out, textsize, ntextreloc);
1088         dumpDATASCNHDR(out, datastart, datasize, ndatareloc);
1089         
1090         // write text section
1091         bca.dump(out);
1092         bca = null; // help GC
1093         
1094         // write text relocs
1095         if (ntextreloc > 65535) {
1096             putUInt(out, ntextreloc);
1097             putUInt(out, 0);
1098             putUShort(out, (char)0);
1099         }
1100         
1101         DataOutput dout = new DataOutputByteBuffer(out);
1102         
1103         Iterator it = text_relocs1.iterator();
1104         while (it.hasNext()) {
1105             Reloc r = (Reloc)it.next();
1106             r.dumpCOFF(dout);
1107         }
1108         it = text_relocs2.iterator();
1109         while (it.hasNext()) {
1110             Reloc r = (Reloc)it.next();
1111             r.dumpCOFF(dout);
1112         }
1113         out.force();
1114         Assert._assert(out.remaining() == 0, "remaining="+out.remaining()+" limit="+out.limit()+" pos="+out.position());
1115         
1116         // write data section
1117         SinglePassBootImage.out.println("Writing bytes "+datastart+".."+(datastart+datasize-1));
1118         heapBuffer.position(0);
1119         heapBuffer.limit(datasize);
1120         fc.write(heapBuffer, datastart);
1121         heapBuffer = null; // to help GC
1122         
1123         SinglePassBootImage.out.println("Writing bytes "+(datastart+datasize)+".."+(strtabstart-1));
1124         out = fc.map(MapMode.READ_WRITE, datastart+datasize, strtabstart - (datastart+datasize));
1125         out.order(ByteOrder.LITTLE_ENDIAN);
1126         dout = new DataOutputByteBuffer(out);
1127         
1128         // write data relocs
1129         int j=0;
1130         if (ndatareloc > 65535) {
1131             putUInt(out, ndatareloc);
1132             putUInt(out, 0);
1133             putUShort(out, (char)0);
1134             ++j;
1135         }
1136         it = data_relocs.iterator();
1137         while (it.hasNext()) {
1138             if ((j % UPDATE_PERIOD) == 0) {
1139                 int bytes = out.position();
1140                 int end = 10*ndatareloc;
1141                 SinglePassBootImage.out.print("Written: "+j+"/"+ndatareloc+" relocations, "+bytes+"/"+end+" bytes\r");
1142             }
1143             Reloc r = (Reloc)it.next();
1144             r.dumpCOFF(dout);
1145             ++j;
1146         }
1147         SinglePassBootImage.out.println("Written: "+ndatareloc+" relocations                                  \n");
1148         Assert._assert(j == ndatareloc);
1149         
1150         // write line numbers
1151         
1152         // write symbol table
1153         dumpSECTIONSYMENTs(out);
1154         dumpEXTSYMENTs(out, rootm);
1155         dumpEXTDEFSYMENTs(out, exts);
1156         it = CodeAllocator.getCompiledMethods();
1157         j=0;
1158         while (it.hasNext()) {
1159             jq_CompiledCode r = (jq_CompiledCode)it.next();
1160             dumpMETHODSYMENT(out, r);
1161             ++j;
1162         }
1163         Assert._assert(j == num_ccs);
1164         
1165         out.force();
1166         Assert._assert(out.remaining() == 0, "remaining="+out.remaining()+" limit="+out.limit()+" pos="+out.position());
1167         
1168         // write string table
1169         int strTabSize = stringTable_size();
1170         SinglePassBootImage.out.println("Writing bytes "+strtabstart+".."+(strtabstart+strTabSize));
1171         out = fc.map(MapMode.READ_WRITE, strtabstart, strTabSize);
1172         out.order(ByteOrder.LITTLE_ENDIAN);
1173         dump_strings(out);
1174         
1175         out.force();
1176         Assert._assert(out.remaining() == 0, "remaining="+out.remaining()+" limit="+out.limit()+" pos="+out.position());
1177         
1178         fc.force(true);
1179     }
1180 
1181     static class UnknownObjectException extends RuntimeException {
1182         /***
1183          * Version ID for serialization.
1184          */
1185         private static final long serialVersionUID = 3258695407449421621L;
1186         Object o; StringBuffer message;
1187         UnknownObjectException(Object o) {
1188             this.o = o;
1189             this.message = new StringBuffer();
1190             this.message.append("type: ");
1191             this.message.append(o.getClass().toString());
1192             this.message.append(" address: ");
1193             this.message.append(Strings.hex(System.identityHashCode(o)));
1194             this.message.append(' ');
1195         }
1196         void setObject(Object o) { this.o = o; }
1197         Object getObject() { return o; }
1198         void prependMessage(String s) {
1199             StringBuffer sb = new StringBuffer();
1200             sb.append(s);
1201             sb.append(this.message);
1202             this.message = sb;
1203         }
1204         void appendMessage(String s) { this.message.append(s); }
1205         public String toString() { return this.message.toString(); }
1206     }
1207 
1208     private jq_StaticField searchStaticVariables(Object p) {
1209         int num = PrimordialClassLoader.loader.getNumTypes();
1210         jq_Type[] types = PrimordialClassLoader.loader.getAllTypes();
1211         for (int i = 0; i < num; ++i) {
1212             Object o = types[i];
1213             if (!(o instanceof jq_Class)) continue;
1214             jq_Class k = (jq_Class) o;
1215             if (!k.isLoaded()) continue;
1216             jq_StaticField[] fs = k.getDeclaredStaticFields();
1217             for (int j=0; j<fs.length; ++j) {
1218                 jq_StaticField f = fs[j];
1219                 if (f.getType().isAddressType()) {
1220                     // not a possible path.
1221                 } else if (f.getType().isReferenceType()) {
1222                     Object val = Reflection.getstatic_A(f);
1223                     if (val == p) return f;
1224                 }
1225             }
1226         }
1227         return null;
1228     }
1229 
1230     private boolean findReferencePath(Object p, UnknownObjectException x, HashSet visited) {
1231         jq_StaticField sf = searchStaticVariables(p);
1232         if (sf != null) {
1233             x.appendMessage(sf.getDeclaringClass()+"."+sf.getName());
1234             return true;
1235         }
1236         Iterator i = hash.keySet().iterator();
1237         while (i.hasNext()) {
1238             IdentityHashCodeWrapper w = (IdentityHashCodeWrapper) i.next();
1239             if (visited.contains(w)) continue;
1240             Object o = w.getObject();
1241             Class objType = o.getClass();
1242             jq_Reference jqType = (jq_Reference)Reflection.getJQType(objType);
1243             if (jqType.isArrayType()) {
1244                 jq_Type elemType = ((jq_Array)jqType).getElementType();
1245                 if (elemType.isAddressType()) {
1246                     // not a possible path.
1247                 } else if (elemType.isReferenceType()) {
1248                     int length = Array.getLength(o);
1249                     Object[] v = (Object[])o;
1250                     for (int k=0; k<length; ++k) {
1251                         Object o2 = Reflection.arrayload_A(v, k);
1252                         if (o2 == p) {
1253                             System.err.println("Possible path: ["+k+"]");
1254                             visited.add(w);
1255                             if (findReferencePath(o, x, visited)) {
1256                                 x.appendMessage("["+k+"]");
1257                                 return true;
1258                             } else {
1259                                 System.err.println("Backtracking ["+k+"]");
1260                             }
1261                         }
1262                     }
1263                 }
1264             } else {
1265                 Assert._assert(jqType.isClassType());
1266                 jq_Class clazz = (jq_Class)jqType;
1267                 jq_InstanceField[] fields = clazz.getInstanceFields();
1268                 for (int k=0; k<fields.length; ++k) {
1269                     jq_InstanceField f = fields[k];
1270                     jq_Type ftype = f.getType();
1271                     if (ftype.isAddressType()) {
1272                         // not a possible path.
1273                     } else if (ftype.isReferenceType()) {
1274                         Object val = Reflection.getfield_A(o, f);
1275                         if (val == p) {
1276                             System.err.println("Possible path: ."+f.getName());
1277                             visited.add(w);
1278                             if (findReferencePath(o, x, visited)) {
1279                                 x.appendMessage("."+f.getName());
1280                                 return true;
1281                             } else {
1282                                 System.err.println("Backtracking ."+f.getName());
1283                             }
1284                         }
1285                     }
1286                 }
1287             }
1288         }
1289         return false;
1290     }
1291     
1292     public static void write_bytes(ByteBuffer out, String s, int len)
1293     throws IOException {
1294         Assert._assert(s.length() <= len);
1295         int i;
1296         for (i=0; ; ++i) {
1297             if (i == s.length()) {
1298                 for (; i<len; ++i) {
1299                     putByte(out, (byte)0);
1300                 }
1301                 return;
1302             }
1303             putByte(out, (byte)s.charAt(i));
1304         }
1305     }
1306     
1307     private String mungeMemberName(jq_Member m) {
1308         String name = m.getDeclaringClass().getName().toString() +
1309                       "_"+m.getName()+
1310                       "_"+m.getDesc();
1311         StringBuffer sb = new StringBuffer();
1312         for (int i = 0; i < name.length(); ++i) {
1313             char c = name.charAt(i);
1314             switch (c) {
1315                 case '.':
1316                 case '/':
1317                 case '(':
1318                 case ')':
1319                 case ';':
1320                     break;
1321                 default:
1322                     sb.append(c);
1323                     break;
1324             }
1325         }
1326         return sb.toString();
1327     }
1328     
1329     int stringTableOffset = 4;
1330     List stringTable = new LinkedList();
1331     private int alloc_string(String name) {
1332         int off = stringTableOffset;
1333         byte[] b = SystemInterface.toCString(name);
1334         stringTable.add(b);
1335         stringTableOffset += b.length;
1336         return off;
1337     }
1338 
1339     private void dump_strings(ByteBuffer out)
1340     throws IOException {
1341         Iterator i = stringTable.iterator();
1342         putUInt(out, stringTableOffset);
1343         while (i.hasNext()) {
1344             byte[] b = (byte[])i.next();
1345             putBytes(out, b);
1346         }
1347     }
1348 
1349     private int stringTable_size() {
1350         int total = 0;
1351         Iterator i = stringTable.iterator();
1352         total += 4;
1353         while (i.hasNext()) {
1354             byte[] b = (byte[])i.next();
1355             total += b.length;
1356         }
1357         return total;
1358     }
1359     
1360     public void dumpELF(FileChannel fc, jq_StaticMethod rootm) throws IOException {
1361         // todo!
1362         MappedByteBuffer bb = fc.map(MapMode.READ_WRITE, 0, 80000000);
1363         bb.order(ByteOrder.LITTLE_ENDIAN);
1364         
1365         final List text_relocs1 = bca.getAllCodeRelocs();
1366         final List text_relocs2 = bca.getAllDataRelocs();
1367         Iterator i = text_relocs1.iterator();
1368         while (i.hasNext()) {
1369             Object r = i.next();
1370             ((Reloc)r).patch();
1371             // directly bound calls do not need to be relocated,
1372             // because they are relative offsets, not absolute addresses.
1373             if (r instanceof DirectBindCall)
1374                 i.remove();
1375         }
1376 
1377         DataOutput out = new DataOutputByteBuffer(bb);
1378         SinglePassBootImage.out.print("Initializing ELF data structures...");
1379         long time = System.currentTimeMillis();
1380         //final int datasize = heapCurrent;
1381         ELFOutput f = new ELFOutput(ELFDATA2LSB, ET_REL, EM_386, 0, out);
1382         f.setLittleEndian();
1383         Section.NullSection empty = Section.NullSection.INSTANCE;
1384         Section.StrTabSection shstrtab = new Section.StrTabSection(".shstrtab", 0, 0);
1385         Section.StrTabSection strtab = new Section.StrTabSection(".strtab", 0, 0);
1386         Section.SymTabSection symtab = new Section.SymTabSection(".symtab", 0, 0, strtab);
1387         Section.ProgBitsSection text = new TextSection();
1388         Section.ProgBitsSection data = new DataSection();
1389         Section.RelSection textrel = new Section.RelSection(".rel.text", 0, 0, symtab, text);
1390         Section.RelSection datarel = new Section.RelSection(".rel.data", 0, 0, symtab, data);
1391         f.setSectionHeaderStringTable(shstrtab);
1392         //f.setSymbolStringTable(strtab);
1393         f.addSection(empty);
1394         f.addSection(shstrtab);
1395         f.addSection(strtab);
1396         f.addSection(symtab);
1397         f.addSection(text);
1398         f.addSection(data);
1399         f.addSection(textrel);
1400         f.addSection(datarel);
1401 
1402         final List exts = new LinkedList();
1403         final int numOfVTableRelocs = addVTableRelocs(data_relocs);
1404         addSystemInterfaceRelocs_ELF(exts, data_relocs);
1405 
1406         symtab.addSymbol(new SymbolTableEntry("", 0, 0, SymbolTableEntry.STB_LOCAL, SymbolTableEntry.STT_NOTYPE, empty));
1407         
1408         SymbolTableEntry textsyment = new SymbolTableEntry("", 0, 0, SymbolTableEntry.STB_LOCAL, SymbolTableEntry.STT_SECTION, text);
1409         SymbolTableEntry datasyment = new SymbolTableEntry("", 0, 0, SymbolTableEntry.STB_LOCAL, SymbolTableEntry.STT_SECTION, data);
1410         symtab.addSymbol(textsyment);
1411         symtab.addSymbol(datasyment);
1412 
1413         Iterator it = exts.iterator();
1414         while (it.hasNext()) {
1415             ExternalReference r = (ExternalReference)it.next();
1416             SymbolTableEntry e = new SymbolTableEntry(r.getName(), 0, 0, SymbolTableEntry.STB_GLOBAL, SymbolTableEntry.STT_FUNC, empty);
1417             symtab.addSymbol(e);
1418             datarel.addReloc(new RelocEntry(r.getAddress().to32BitValue(), e, RelocEntry.R_386_32));
1419         }
1420 
1421         it = CodeAllocator.getCompiledMethods();
1422         while (it.hasNext()) {
1423             jq_CompiledCode cc = (jq_CompiledCode)it.next();
1424             jq_Method m = cc.getMethod();
1425             String name;
1426             if (m == null) {
1427                 name = "unknown@"+cc.getEntrypoint().stringRep();
1428             } else {
1429                 name = mungeMemberName(m);
1430             }
1431             SymbolTableEntry e = new SymbolTableEntry(name, cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_LOCAL, STT_FUNC, text);
1432             symtab.addSymbol(e);
1433         }
1434 
1435         {
1436             jq_CompiledCode cc = rootm.getDefaultCompiledVersion();
1437             SymbolTableEntry e = new SymbolTableEntry("entry", cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_GLOBAL, STT_FUNC, text);
1438             symtab.addSymbol(e);
1439 
1440             cc = ExceptionDeliverer._trap_handler.getDefaultCompiledVersion();
1441             e = new SymbolTableEntry("trap_handler", cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_GLOBAL, STT_FUNC, text);
1442             symtab.addSymbol(e);
1443 
1444             cc = ExceptionDeliverer._debug_trap_handler.getDefaultCompiledVersion();
1445             e = new SymbolTableEntry("debug_trap_handler", cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_GLOBAL, STT_FUNC, text);
1446             symtab.addSymbol(e);
1447             
1448             cc = jq_NativeThread._threadSwitch.getDefaultCompiledVersion();
1449             e = new SymbolTableEntry("threadSwitch", cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_GLOBAL, STT_FUNC, text);
1450             symtab.addSymbol(e);
1451 
1452             cc = jq_NativeThread._ctrl_break_handler.getDefaultCompiledVersion();
1453             e = new SymbolTableEntry("ctrl_break_handler", cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_GLOBAL, STT_FUNC, text);
1454             symtab.addSymbol(e);
1455 
1456             e = new SymbolTableEntry("joeq_code_startaddress", 0, 0, STB_GLOBAL, STT_OBJECT, text);
1457             symtab.addSymbol(e);
1458 
1459             e = new SymbolTableEntry("joeq_code_endaddress", bca.size(), 0, STB_GLOBAL, STT_OBJECT, text);
1460             symtab.addSymbol(e);
1461 
1462             e = new SymbolTableEntry("joeq_data_startaddress", 0, 0, STB_GLOBAL, STT_OBJECT, data);
1463             symtab.addSymbol(e);
1464 
1465             e = new SymbolTableEntry("joeq_data_endaddress", heapCurrent, 0, STB_GLOBAL, STT_OBJECT, data);
1466             symtab.addSymbol(e);
1467         }
1468 
1469         it = text_relocs1.iterator();
1470         while (it.hasNext()) {
1471             Reloc r = (Reloc)it.next();
1472             if (r instanceof Code2CodeReference) {
1473                 Code2CodeReference cr = (Code2CodeReference)r;
1474                 textrel.addReloc(new RelocEntry(cr.getFrom().to32BitValue(), datasyment, RelocEntry.R_386_32));
1475             } else {
1476                 Assert.UNREACHABLE(r.toString());
1477             }
1478         }
1479         
1480         it = text_relocs2.iterator();
1481         while (it.hasNext()) {
1482             Reloc r = (Reloc)it.next();
1483             if (r instanceof Code2HeapReference) {
1484                 Code2HeapReference cr = (Code2HeapReference)r;
1485                 textrel.addReloc(new RelocEntry(cr.getFrom().to32BitValue(), datasyment, RelocEntry.R_386_32));
1486             } else {
1487                 Assert.UNREACHABLE(r.toString());
1488             }
1489         }
1490         
1491         it = data_relocs.iterator();
1492         while (it.hasNext()) {
1493             Reloc r = (Reloc)it.next();
1494             if (r instanceof Heap2HeapReference) {
1495                 Heap2HeapReference cr = (Heap2HeapReference)r;
1496                 datarel.addReloc(new RelocEntry(cr.getFrom().to32BitValue(), datasyment, RelocEntry.R_386_32));
1497             } else if (r instanceof Heap2CodeReference) {
1498                 Heap2CodeReference cr = (Heap2CodeReference)r;
1499                 datarel.addReloc(new RelocEntry(cr.getFrom().to32BitValue(), textsyment, RelocEntry.R_386_32));
1500             } else if (r instanceof ExternalReference) {
1501                 // already done.
1502             } else {
1503                 Assert.UNREACHABLE(r.toString());
1504             }
1505         }
1506         
1507         time = System.currentTimeMillis() - time;
1508         SinglePassBootImage.out.println("done. ("+(time/1000.)+" seconds)");
1509         
1510         f.write();
1511         int pos = bb.position();
1512         bb.force();
1513         fc.truncate(pos);
1514     }
1515 
1516     class TextSection extends Section.ProgBitsSection {
1517         TextSection() {
1518             super(".text", Section.SHF_ALLOC | Section.SHF_EXECINSTR | Section.SHF_WRITE, 0);
1519         }
1520         public int getSize() { return bca.size(); }
1521         public int getAddrAlign() { return 64; }
1522         public void writeData(ELF file) throws IOException {
1523             DataOutput out = (DataOutput) ((ELFOutput)file).getOutput();
1524             bca.dump(out);
1525         }
1526         public void load(Section.UnloadedSection s, ELF file) throws IOException {
1527             Assert.UNREACHABLE();
1528         }
1529     }
1530 
1531     class DataSection extends Section.ProgBitsSection {
1532         DataSection() {
1533             super(".data", Section.SHF_ALLOC | Section.SHF_WRITE, 0);
1534         }
1535         public int getSize() { return heapCurrent; }
1536         public int getAddrAlign() { return 64; }
1537         public void writeData(ELF file) throws IOException {
1538             try {
1539                 DataOutput out = (DataOutput) ((ELFOutput)file).getOutput();
1540                 byte[] b;
1541                 if (heapBuffer.hasArray()) b = heapBuffer.array();
1542                 else {
1543                     b = new byte[heapCurrent];
1544                     heapBuffer.position(0);
1545                     heapBuffer.get(b);
1546                 }
1547                 out.write(b);
1548             } catch (UnknownObjectException x) {
1549                 Object u = x.getObject();
1550                 HashSet visited = new HashSet();
1551                 findReferencePath(u, x, visited);
1552                 throw x;
1553             }
1554         }
1555         public void load(Section.UnloadedSection s, ELF file) throws IOException {
1556             Assert.UNREACHABLE();
1557         }
1558     }
1559     
1560     public static final jq_StaticField _DEFAULT;
1561     static {
1562         jq_Class k = (jq_Class) PrimordialClassLoader.loader.getOrCreateBSType("Ljoeq/Bootstrap/SinglePassBootImage;");
1563         _DEFAULT = k.getOrCreateStaticField("DEFAULT", "Ljoeq/Bootstrap/SinglePassBootImage;");
1564     }
1565 
1566 }